﻿#if !MONOGAME

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Brain.Rendering;

namespace Brain.Ballistics3D
{
    public class DefaultBulletRendererModel3D : IBulletRenderer3D
    {
        protected VertexBuffer VertexBuffer;
        protected IndexBuffer IndexBuffer;

        protected Effect Effect;

        public event SetEffectParameters OnSetEffectParameters;

        public InstancingSystem Instancing;
        private Vector3[] Shots;

        /// <summary>
        /// Stufff
        /// </summary>
        internal static VertexDeclaration instanceVertexDeclaration = new VertexDeclaration
        (
            new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Fog, 0)
        );

        public DefaultBulletRendererModel3D(VertexBuffer vBuffer, IndexBuffer iBuffer, Effect instancingEffect)
        {
#if MONOGAME
            Instancing = new InstancingSystem(vBuffer, iBuffer, instanceVertexDeclaration, typeof(Vector3));
#else
            Instancing = new InstancingSystem(vBuffer, iBuffer, instanceVertexDeclaration);
#endif
            this.ManagerUpdatesBullets = false;

            this.VertexBuffer = vBuffer;
            this.IndexBuffer = iBuffer;

            this.Effect = instancingEffect;
        }

        public void UpdateParticle(Bullet3D bullet, int index)
        {
            Shots[index] = bullet.Position;
        }

        public void Render(BulletManager3D bulletManager)
        {
            ICamera3D Camera = Engine.Instance.CameraManager.Camera3D;
            if (Camera != null)
            {
                GraphicsDevice device = Engine.Instance.GraphicsDevice;
                device.BlendState = BlendState.AlphaBlend;
                device.DepthStencilState = DepthStencilState.Default;

                if (Shots == null ||
                    Shots.Length != bulletManager.Bullets.Length)
                {
                    Shots = new Vector3[bulletManager.Bullets.Length];
                }

                for (int i = 0; i < bulletManager.Bullets.Length; i++)
                {
                    Bullet3D bullet = bulletManager.Bullets[i];
                    if (bullet.Active)
                    {
                        if (!this.ManagerUpdatesBullets)
                        {
                            bullet.Update();
                            Shots[i] = bullet.Position;
                        }
                    }
                }
                Instancing.ResizeBufferIfNotBig(bulletManager.Bullets.Length);

                Instancing.InstancesVertexBuffer.SetData(this.Shots);
                
                device.SetVertexBuffers(new VertexBufferBinding(Instancing.ModelVertexBuffer, 0, 0),
                                        new VertexBufferBinding(Instancing.InstancesVertexBuffer, 0, 1));
                device.Indices = Instancing.ModelIndexBuffer;

                if (OnSetEffectParameters != null)
                {
                    OnSetEffectParameters(this.Effect, Camera, this);
                }

                foreach (EffectPass pass in Effect.CurrentTechnique.Passes)
                {
                    pass.Apply();

                    device.DrawInstancedPrimitives(PrimitiveType.TriangleList,
                        0, 0, Instancing.ModelVertexBuffer.VertexCount, 0, Instancing.ModelIndexBuffer.IndexCount / 3, Instancing.InstancesVertexBuffer.VertexCount);
                }

                device.SetVertexBuffer(null);
                device.Indices = null;
            }
        }

        public bool ManagerUpdatesBullets { get; set; }
    }
}

#endif